1

上一个版本的问题

这篇文章,聊聊参数检查工具 param-check 的完善。

按照之前的接口设计,链式调用表示“与”,参数表表示“或”,自然产生了一个问题——如果我要表达“(A与B)或(C与D)”这样的逻辑组合应该怎么办?

以及,由于 not 调用只对它后面的第一个调用生效,那么如果我要实现“非(A与B)”,该怎么办?

总结起来,实际上就是给逻辑表达式加括号的问题。

or 和 and 方法

为了自由表达与或关系,我们需要扩展一下规则。分析可知,函数调用的参数表是一个天然的括号,所以只用来表达“或”太奢侈了。我们添加方法 or 和 and,使之能表达与和或。但是这里有个问题,param-check 目前的接口都是即时计算的,如果你把调用串当做参数传递,没有传进去之前已经计算完了,异常捕获不到,没法实现逻辑关系。比如:

check(a).or(check(a).gt(1).lt(3), check(a).gt(2).lt(4));

上面的代码是没法实现 or 的。

解决方法比较容易想到的有两个:

  1. 改变接口模式,不再抛出异常,二是返回 false。这样 or 和 and 就很容易实现了,但是链式调用就没法实现了。

  2. 提取 check 的调用路径,使得一个检查过程能保存在一个对象(高阶函数)里,当做参数传到其它函数中,本质上这是一种函数式编程方法。如果不考虑到书写方便,这是很容易实现的:

    function myCheck(a) {
        check(a).gt(1).lt(3);
    }
    
    function myCheck2(a) {
        check(a).is('string');
    }
    
    +function (a) {
        check(a).or(myCheck, myCheck2);
    }(2);

“使用链式调用记录链式调用路径”

显然上面的写法非常不方便,所以我实现了一种更好用的接口,使用同样的链式调用方式,实现调用路径提取和参数缓存。具体的实现方式在这篇文章里。最终实现了这样的效果:

// 检查 param 是否在区间(1,3) 与 (2,4) 的交集内
check(param, 'param').and(check.policy.gt(1).lt(3), check.policy.gt(2).lt(4));

// 检查 param 是否在区间(1,2) 与 (3,4) 的并集内
check(param, 'param').or(check.policy.gt(1).lt(2), check.policy.gt(3).lt(4));

function myCheck(obj) {
    return obj.length > 4;
}

// 检查 param 是否是数组并且长度大于 4
check(param, 'param').and(check.policy.is('array'), myCheck);

// 检查 param 是否*不是*[1,3]之间的偶数(即2)
check(param, 'param').not.and(
    check.policy.is('number').not.lt(1).not.gt(3),
    function (obj) {
        return obj % 2 === 0;
    });

Y3G
458 声望14 粉丝

桌面软件、 web前端、 移动app混合开发、 安防行业技术